package cn.buk.tms.eotms.service;

import cn.buk.api.hotel.request.HotelAvailRequest;
import cn.buk.api.hotel.response.RoomPrice;
import cn.buk.api.pay.alipay.service.AlipayService;
import cn.buk.common.JsonResult;
import cn.buk.common.util.DateUtil;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.eotms.dao.HotelOrderDao;
import cn.buk.tms.eotms.dao.OrderNoGenerator;
import cn.buk.tms.eotms.dao.PaymentOrderDao;
import cn.buk.tms.eotms.dto.RoleInfo;
import cn.buk.tms.eotms.request.HotelOrderRequestDto;
import cn.buk.tms.eotms.dto.HotelOrderPassengerDto;
import cn.buk.tms.eotms.entity.HotelOrder;
import cn.buk.tms.eotms.entity.HotelOrderPrice;
import cn.buk.tms.eotms.entity.PaymentOrder;
import cn.buk.tms.eotms.response.HotelOrderResponseDto;
import cn.buk.tms.eotms.sc.HotelOrderSearchCriteria;
import cn.buk.tms.eotms.util.ValidationUtils;
import cn.buk.tms.hotel.dto.HotelAvailDto;
import cn.buk.tms.hotel.util.HttpUtil;
import com.alibaba.fastjson.JSON;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static cn.buk.tms.common.constant.TmsOrderConstant.*;

@Service
public class HotelOrderServiceImpl extends BaseAbstractService implements HotelOrderService {

  private static final Logger logger = Logger.getLogger(HotelOrderServiceImpl.class);

  /**
   * 调用酒店接口时的接口地址
   */
  private final String apiUrl;

  @Autowired
  public HotelOrderServiceImpl(
          @Value("${api_hotel_url}") String apiUrl,
          HotelOrderDao hotelOrderDao,
                               OrderNoGenerator orderNoGenerator,
                               PaymentOrderDao paymentOrderDao,
                               AlipayService alipayService) {
    this.apiUrl = apiUrl;
    this.hotelOrderDao = hotelOrderDao;
    this.orderNoGenerator = orderNoGenerator;
    this.paymentOrderDao = paymentOrderDao;
    this.alipayService = alipayService;
  }

  private final HotelOrderDao hotelOrderDao;

  private final OrderNoGenerator orderNoGenerator;

  private final PaymentOrderDao paymentOrderDao;
  private final AlipayService alipayService;

  @Override
  public List<HotelOrderResponseDto> searchHotelOrders(int userId, HotelOrderSearchCriteria sc) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);
    final int enterpriseId = getEnterpriseIdByUserId(userId);
    final String username = getUsernameByUserId(userId);

    Set<String> roles = getRolesByUserId(enterpriseId, userId);
    //管理员可以查看所有的员工信息
    //其它可以查看本部门所有的员工信息
    if (roles.contains(RoleInfo.ROLE_ADMIN)) {
      //管理员可以查看所有部门的订单
    } else if (roles.contains(RoleInfo.ROLE_MANAGER) || roles.contains(RoleInfo.ROLE_APPROVER)){
      //只能查看本部门的
      int deptId = getCustomerDeptIdByUserId(userId);
      sc.setDepartmentId(deptId);
    } else {
      //只能查看自己的订单
      sc.setOp1(username);
    }

    List<HotelOrder> orders = hotelOrderDao.searchHotelOrders(ownerId, customerId, sc);

    List<HotelOrderResponseDto> dtos = new ArrayList<>();
    for(HotelOrder order: orders) {
      dtos.add(HotelOrderResponseDto.createByHotelOrder(order));
    }

    return dtos;
  }

  @Override
  public HotelOrderResponseDto getHotelOrderById(int userId, int orderId) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    HotelOrder o = hotelOrderDao.getHotelOrderById(orderId);

    if (o == null) {
      return null;
    }

    if (o.getEnterpriseId() != ownerId || o.getCustomer().getId() != customerId) {
      return null;
    }

    return HotelOrderResponseDto.createByHotelOrder(o);
  }

  @Override
  public JsonResult createHotelOrder(final int userId, HotelOrderRequestDto dto) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);
    final String username = getUsernameByUserId(userId);

    if (customerId < 1) {
      return JsonResult.createJsonResult(-1, "客户信息不正确。");
    }

    dto.processPassengerInfo();

    try {
      ValidationUtils.validate(dto);
      for (HotelOrderPassengerDto psgDto : dto.getPassengers()) {
        ValidationUtils.validate(psgDto);
      }
    } catch (Exception ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-1, ex.getMessage());
    }

    if (dto.getCheckInDate().getTime() >= dto.getCheckOutDate().getTime()) {
      return JsonResult.createJsonResult(-2, "入住日期需要早于离店日期");
    }

    if (dto.getPassengers().size() < dto.getRoomCount()) {
      return JsonResult.createJsonResult(-3, "入住人数需要大于等于房间数");
    }

    if (dto.getLastArriveTime() != null && dto.getLastArriveTime().trim().length() < 5) {
      return JsonResult.createJsonResult(-4, "请检查最晚到店时间");
    }

    //入住天数要和每日价格数量一致
    final int days = DateUtil.getPastDays(dto.getCheckOutDate(), dto.getCheckInDate());
    if (days != dto.getPrices().size()) {
      return JsonResult.createJsonResult(-4, "入住晚数需要同每晚价格数一致");
    }


    //校验总价
    final double totalAmount = dto.getTotalAmount();
    dto.calc();
    double alpha = Math.abs(totalAmount - dto.getTotalAmount());
    if (alpha > 0.01) {
      return JsonResult.createJsonResult(-5, "订单总额误差过大：" + totalAmount + ", " + dto.getTotalAmount());
    }

    dto.setCustomerId(customerId);
    dto.setOperator(username);

    HotelOrder hotelOrder = HotelOrderRequestDto.convertToHotelOrder(dto);
    hotelOrder.setEnterpriseId(ownerId);

    //TODO 调用接口预订的，是不是要调用checkAvail接口？
    //TODO 此处调用接口需要填写和代理通的结算价
    JsonResult jsonResult = checkAvailableHotel(hotelOrder);
      if (!JsonResult.STATUS_OK.equalsIgnoreCase(jsonResult.getStatus())) {
        logger.error(jsonResult.getErrcode() + ": " + jsonResult.getErrmsg());
//        return jsonResult;
      }

    // 订单号
    hotelOrder.setOrderNo(orderNoGenerator.generateOrderNo(ownerId, TmsOrderConstant.ORDER_NO_HOTEL_SELF_SERVICE));

    try {
      int retCode = hotelOrderDao.createHotelOrder(hotelOrder);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      logger.error(ex.getMessage());
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public JsonResult cancelHotelOrder(int userId, int orderId, String remark) {

    return JsonResult.createJsonResult(-10, "暂时无法取消该订单，请联系客服");

//    final int ownerId = getOwnerIdByUserId(userId);
//    final int customerId = getCustomerIdByUserId(userId);
//    final String username = getUsernameByUserId(userId);
//
//    try {
//      int retCode = hotelOrderDao.cancelHotelOrder(ownerId, customerId, username, orderId, remark);
//      return JsonResult.createJsonResult(retCode);
//    } catch (RuntimeException ex) {
//      return JsonResult.createJsonResult(-100, ex.getMessage());
//    }
  }

  @Override
  public JsonResult submitHotelOrder(int userId, int orderId) {
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);
    final String username = getUsernameByUserId(userId);

    try {
      int retCode = hotelOrderDao.submitHotelOrder(ownerId, customerId, username, orderId);
      return JsonResult.createJsonResult(retCode);
    } catch (RuntimeException ex) {
      return JsonResult.createJsonResult(-100, ex.getMessage());
    }
  }

  @Override
  public JsonResult approveHotelOrder(final int userId, final int orderId, final int denyCode, final String denyReason) {
    if (denyCode != 0 && (denyReason == null || denyReason.trim().length() < 3 )) {
      return JsonResult.createJsonResult(-1, "请输入拒绝的原因");
    }
    final int ownerId = getOwnerIdByUserId(userId);
    final int customerId = getCustomerIdByUserId(userId);

    HotelOrder hotelOrder = hotelOrderDao.getHotelOrderById(orderId);
    if (customerId != hotelOrder.getCustomer().getId()) {
      return JsonResult.createJsonResult(-2, "订单不存在");
    }

    //判断审批人是否有权审批

    final String username = getUsernameByUserId(userId);
    //1.是指定的审批人
    if (hotelOrder.getApprovalInfo() != null &&
            username.equalsIgnoreCase(hotelOrder.getApprovalInfo().getSpecifiedApprover())) {
      int retCode = hotelOrderDao.approveHotelOrder(ownerId, customerId, username, orderId, denyCode, denyReason);
      return JsonResult.createJsonResult(retCode);
    }

    //TODO
    //2.如果不是，就是部门审批人
    //3.如果不是，就是主账户
    final int enterpriseId = getEnterpriseIdByUserId(userId);
    if (enterpriseId == userId) {
      int retCode = hotelOrderDao.approveHotelOrder(ownerId, customerId, username, orderId, denyCode, denyReason);
      return JsonResult.createJsonResult(retCode);
    }

    //4.都不是，提示无权审批

    return JsonResult.createJsonResult(-1, "您不是指定审批人");

//    return null;
  }

  @Override
  public JsonResult payHotelOrder(final int userId, final int orderId) {
    HotelOrderResponseDto orderDto = this.getHotelOrderById(userId, orderId);
    if (orderDto == null) {
      return JsonResult.createJsonResult(-1, "无此订单");
    }

    if (orderDto.getPayType() != PAY_TYPE_CASH) {
      return JsonResult.createJsonResult(-1, "该订单的付款方式非现金方式");
    }

    if (orderDto.getPriceCheckedStatus() != 1) {
      return JsonResult.createJsonResult(-2, "订单还在校验中，请稍等...");
    }

    final int enterpriseId = getEnterpriseIdByUserId(userId);
    final int ownerId = getOwnerIdByUserId(userId);

    //支付订单号
    // 10 - 支付宝支付
    // 20 - 表示微信支付
    String outTradeNo = "10"+ enterpriseId + "0" + + userId + "0" + DateUtil.getCurDateTimeString("yyyyMMddHHmmss");
    //商户网站订单系统中唯一订单号，必填

    //订单名称
    final String subject = "酒店订单付款";
    //必填

    //保存支付订单
    PaymentOrder order = new PaymentOrder();
    order.setEnterpriseId(enterpriseId);
    order.setUserId(userId);
    order.setOwnerEnterpriseId(ownerId);
    order.setTradeNo(outTradeNo);
    order.setPrice(orderDto.getTotalAmount());
    order.setStatus(0);
    order.setMemo(subject);
    order.setOrderType(ORDER_TYPE_HOTEL);
    order.setOrderId(orderId);

    JsonResult jsonResult = new JsonResult();

    jsonResult.setStatus("OK");
    int retCode = paymentOrderDao.create(order);

    String url = alipayService.createPaymentParams(outTradeNo, orderDto.getTotalAmount(), subject);

    logger.info(url);

    jsonResult.setUrl(url);

    return jsonResult;
  }

  /**
   * 调用酒店接口检查是否可用
   * TODO 此方法和tms中的一样，看看是否可以重构
   * @param hotelOrder
   * @return
   */
  private JsonResult checkAvailableHotel(HotelOrder hotelOrder) {
    HotelAvailRequest request = new HotelAvailRequest();

    int supplierHotelId = doGetSupplierHotelId(hotelOrder.getHotelId());
    int supplierRoomId = doGetSupplierRoomId(hotelOrder.getRoomId());

    request.setHotelId(supplierHotelId);
    request.setRoomId(supplierRoomId + "");

    request.setQuantity(hotelOrder.getRoomCount());
    request.setPersons(hotelOrder.getPsgCount());
    //向供应商提交的金额是成本金额
    request.setTotalAmount(hotelOrder.getTotalCost());


//    request.getDateRange().setStart(LocalDateTime.parse(DateUtil.formatDate(hotelOrder.getCheckInDate(), "yyyy-MM-dd") + "T00:00:00"));
//    request.getDateRange().setEnd(LocalDateTime.parse(DateUtil.formatDate(hotelOrder.getCheckOutDate(), "yyyy-MM-dd") + "T00:00:00"));

    for (HotelOrderPrice orderPrice : hotelOrder.getPrices()) {
      RoomPrice roomPrice = new RoomPrice();

      roomPrice.setEffectiveDate(orderPrice.getEffectiveDate());
      roomPrice.setCurrency(orderPrice.getCurrency());
      roomPrice.setInclusiveAmount(orderPrice.getInclusiveAmount());
      roomPrice.setMealType(orderPrice.getMealType());
      roomPrice.setMealCount(orderPrice.getMealCount());

      request.getEverydayPrices().add(roomPrice);
    }

    final String postStr = JSON.toJSONString(request);
    final String url = apiUrl + "/hotel/avail";
    final String jsonStr = HttpUtil.postUrl(url, postStr, true);

    HotelAvailDto rs = JSON.parseObject(jsonStr, HotelAvailDto.class);

    if (rs != null) {
      if (rs.isStatus()) {
        if (rs.getMessage() != null && rs.getMessage().trim().length() > 0) {
          return JsonResult.createJsonResult(1, rs.getMessage());
        } else {
          return JsonResult.createJsonResult(1);
        }
      } else {
        return JsonResult.createJsonResult(-1, rs.getMessage());
      }
    } else {
      return JsonResult.createJsonResult(-1, "可定性检查失败");
    }

  }

  private int doGetSupplierRoomId(int roomId) {
    final String url = apiUrl + "/room/" + roomId + "/supplierRoomId";
    String val = HttpUtil.getUrl(url, null);
    return Integer.parseInt(val);
  }

  private int doGetSupplierHotelId(int hotelId) {
//        /hotel/{hotelId}/supplierHotelId
    final String url = apiUrl + "/hotel/" + hotelId + "/supplierHotelId";
    logger.warn(url);
    String val = HttpUtil.getUrl(url, null);

    return Integer.parseInt(val);
  }
}
